package org.liquidByte.trafficMustang.androidApp.activities;

import java.util.concurrent.TimeUnit;

import org.liquidByte.trafficMustang.R;
import org.liquidByte.trafficMustang.androidApp.LocationTracker;
import org.liquidByte.trafficMustang.androidApp.overlays.SelectableOverlay;
import org.liquidByte.trafficMustang.androidApp.overlays.TrackingOverlay;
import org.liquidByte.trafficMustang.androidApp.overlays.TrackingOverlay.Tracker;
import org.liquidByte.trafficMustang.androidApp.services.RastreamentoService;
import org.liquidByte.trafficMustang.androidApp.services.Services;
import org.liquidByte.trafficMustang.androidApp.services.dto.LocalizacaoDTO;
import org.liquidByte.trafficMustang.androidApp.services.dto.UsuarioDTO;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.location.Location;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;

public class VisualizarLocalizacaoActivity extends MapActivity implements OnClickListener {
	
	public static final int INITIAL_ZOOM_LEVEL = 15;
	public static final long TRACKING_INITIAL_DELAY = 0;
	public static final long TRACKING_DELAY = 5;
	public static final TimeUnit TRACKING_TIME_UNIT = TimeUnit.SECONDS;
	
	private ImageButton imgbConfirmar;
	private ImageButton imgbCancelar;
	private ImageButton imgbZoomIn;
	private ImageButton imgbZoomOut;
	private MapView mapView;
	private Bitmap pushpin;
	private VisualizarLocalizacaoStrategy strategy;
	
	protected Bitmap getPushpin() {
		if (this.pushpin == null) {
			this.pushpin = BitmapFactory.decodeResource(this.getResources(), R.drawable.pushpin);
		}
		return this.pushpin;
	}
	protected MapView getMapView() {
		if (this.mapView == null) {
			this.mapView = (MapView)this.findViewById(R.id.activity_visualizar_localizacao_mapView);
		}
		return mapView;
	}
	protected ImageButton getImgbConfirmar() {
		if (this.imgbConfirmar == null) {
			this.imgbConfirmar = (ImageButton)this.findViewById(R.id.activity_visualizar_localizacao_imgbConfirmar);
		}
		return imgbConfirmar;
	}
	protected ImageButton getImgbCancelar() {
		if (this.imgbCancelar == null) {
			this.imgbCancelar = (ImageButton)this.findViewById(R.id.activity_visualizar_localizacao_imgbCancelar);
		}
		return imgbCancelar;
	}
	protected ImageButton getImgbZoomIn() {
		if (this.imgbZoomIn == null) {
			this.imgbZoomIn = (ImageButton)this.findViewById(R.id.activity_visualizar_localizacao_zoomIn);
		}
		return imgbZoomIn;
	}
	protected ImageButton getImgbZoomOut() {
		if (this.imgbZoomOut == null) {
			this.imgbZoomOut = (ImageButton)this.findViewById(R.id.activity_visualizar_localizacao_zoomOut);
		}
		return imgbZoomOut;
	}
	protected VisualizarLocalizacaoStrategy getStrategy() {
		return this.strategy;
	}
	protected void setStrategy(VisualizarLocalizacaoStrategy strategy) {
		if (!(this.strategy == null && strategy == null ||
			  this.strategy != null && strategy != null && this.strategy.equals(strategy))) {
			if (this.strategy != null) {
				this.strategy.destroy();
			}
			this.strategy = strategy;
			if (this.strategy != null) {
				this.strategy.init();
			}
		}
	}
	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}
	
	private static LocalizacaoDTO fromGeoPoint(GeoPoint point) {
		LocalizacaoDTO dto = new LocalizacaoDTO();
		dto.setLatitude(point.getLatitudeE6() / 1E6);
		dto.setLongitude(point.getLongitudeE6() / 1E6);
		return dto;
	}

	
	private static GeoPoint toGeoPoint(LocalizacaoDTO location) {
		if (location == null) {
			return null;
		} else {
			return new GeoPoint((int)(location.getLatitude() * 1E6), (int)(location.getLongitude() * 1E6));
		}
	}
	
	private static GeoPoint toGeoPoint(Location location) {
		if (location == null) {
			return null;
		} else {
			return new GeoPoint((int)(location.getLatitude() * 1E6), (int)(location.getLongitude() * 1E6));
		}
	}

	private void centerOnMyLocation() {
		Location location = LocationTracker.getInstance().getLastKnown();
		
		if (location != null) {
			this.getMapView().getController().setCenter(VisualizarLocalizacaoActivity.toGeoPoint(location));
		}
	}
	private void defaultZoom() {
		this.getMapView().getController().setZoom(INITIAL_ZOOM_LEVEL);
	}
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		this.setContentView(R.layout.activity_visualizar_localizacao);
		
		this.getImgbCancelar().setOnClickListener(this);
		this.getImgbZoomIn().setOnClickListener(this);
		this.getImgbZoomOut().setOnClickListener(this);
		this.getImgbConfirmar().setVisibility(View.GONE);

		UsuarioDTO usuario = (UsuarioDTO)this.getIntent().getSerializableExtra(UsuarioDTO.class.getName());
		if (usuario == null) {
			this.setStrategy(new SelectableStrategy(this));
		} else {
			this.setStrategy(new TrackingStrategy(this, new UsuarioTracker(usuario)));
		}
	}
	@Override
	public void onClick(View v) {
		if (this.getImgbCancelar() == v) {
			this.cancel();
		} else if (this.getImgbZoomIn() == v) {
			this.zoomIn();
		} else if (this.getImgbZoomOut() == v) {
			this.zoomOut();
		}
	}
	@Override
	public void finish() {
		this.setStrategy(null);
		super.finish();
	}
	private void cancel() {
		this.setResult(Activity.RESULT_CANCELED);
		this.finish();
	}
	private void zoomIn() {
		this.getMapView().getController().zoomIn();
	}
	private void zoomOut() {
		this.getMapView().getController().zoomOut();
	}
	
	private interface VisualizarLocalizacaoStrategy {
		void init();
		void destroy();
	}	
	private class SelectableStrategy implements VisualizarLocalizacaoStrategy, OnClickListener {
		
		private VisualizarLocalizacaoActivity parent;
		private SelectableOverlay overlay;

		private SelectableStrategy(VisualizarLocalizacaoActivity parent) {
			if (parent == null) {
				throw new IllegalArgumentException("parent is null");
			}
			this.parent = parent;
		}
		
		protected SelectableOverlay getOverlay() {
			if (this.overlay == null) {
				this.overlay = new SelectableOverlay(this.parent.getPushpin());
			}
			return overlay;
		}

		private void confirm() {
			GeoPoint point = this.getOverlay().getMark();
			if (point != null) {
				Intent intent = new Intent();
				intent.putExtra(LocalizacaoDTO.class.getName(), VisualizarLocalizacaoActivity.fromGeoPoint(point));
				this.parent.setResult(Activity.RESULT_OK, intent);
			}
			this.parent.finish();
		}
		
		@Override
		public void init() {
			this.parent.getImgbConfirmar().setVisibility(View.VISIBLE);
			this.parent.getImgbConfirmar().setOnClickListener(this);
			
			this.parent.getMapView().getOverlays().add(this.getOverlay());
			
			this.parent.centerOnMyLocation();
			this.parent.defaultZoom();
		}

		@Override
		public void destroy() {
			this.parent.getImgbConfirmar().setVisibility(View.GONE);
			this.parent.getImgbConfirmar().setOnClickListener(null);
			
			this.parent.getMapView().getOverlays().remove(this.getOverlay());
		}
		
		@Override
		public void onClick(View v) {
			if (v == this.parent.getImgbConfirmar()) {
				this.confirm();
			}
		}
	}
	private class TrackingStrategy implements VisualizarLocalizacaoStrategy {

		private VisualizarLocalizacaoActivity parent;
		private TrackingOverlay overlay;
		private Tracker tracker;
		
		private TrackingStrategy(VisualizarLocalizacaoActivity parent, Tracker tracker) {
			if (parent == null) {
				throw new IllegalArgumentException("parent is null");
			}
			if (tracker == null) {
				throw new IllegalArgumentException("tracker is null");
			}
			this.parent = parent;
			this.tracker = tracker;
		}
		
		protected TrackingOverlay getOverlay() {
			if (this.overlay == null) {
				this.overlay = new TrackingOverlay(this.parent, this.parent.getMapView(), this.parent.getPushpin(),
								 				   this.tracker, TRACKING_INITIAL_DELAY, TRACKING_DELAY, TRACKING_TIME_UNIT, true);
			}
			return overlay;
		}



		@Override
		public void init() {
			this.parent.getMapView().getOverlays().add(this.getOverlay());
			this.parent.defaultZoom();
			this.getOverlay().start();
		}

		@Override
		public void destroy() {
			this.getOverlay().stop();	
			this.parent.getMapView().getOverlays().remove(this.getOverlay());
		}
	}
	
	private class UsuarioTracker implements Tracker {
		
		private UsuarioDTO usuario;
		
		private UsuarioTracker(UsuarioDTO usuario) {
			if (usuario == null) {
				throw new IllegalArgumentException("usuario is null");
			}
			this.usuario = usuario;
		}

		@Override
		public GeoPoint getLocation() {
			RastreamentoService service = Services.rastreamento();
			LocalizacaoDTO localizacao;
			try {
				localizacao = service.getLocation(this.usuario);
			} catch (Exception e) {
				return null;
			}
			return VisualizarLocalizacaoActivity.toGeoPoint(localizacao);
		}
	}
}
